package com.ibm.cloud.banking.trans.account;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibm.cloud.banking.account.entity.AccountInfo;
import com.ibm.cloud.banking.facade.account.IAccountFacade;
import com.ibm.cloud.banking.facade.account.dto.AccountBalanceUpdateDTO;
import com.ibm.cloud.banking.facade.account.dto.AccountInfoDTO;
import com.ibm.cloud.banking.facade.account.dto.AccountLimitAmtTxSumDTO;
import com.ibm.cloud.banking.facade.media.IMediaCardFacade;
import com.ibm.cloud.banking.facade.media.dto.MediaCardDTO;
import com.ibm.cloud.banking.parameter.pricing.entity.*;
import com.ibm.cloud.banking.parameter.pricing.service.PricingChargingInnerServiceImpl;
import com.ibm.cloud.banking.prod.dto.ProductCheckDTO;
import com.ibm.cloud.banking.prod.service.ProductParameterQueryServiceImpl;
import com.ibm.cloud.banking.trans.account.dto.Req111227;
import com.ibm.cloud.banking.trans.account.dto.Resp111227;
import com.ibm.cloud.banking.utils.ValueCopyUtils;
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.Synchronization;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

// 交易异常时，同步补偿
@Configuration
public class Trans111227 extends RouteBuilder {

    @Resource
    IAccountFacade accountFacade;

    @Resource
    IMediaCardFacade mediaCardFacade;

    @Resource
    PricingChargingInnerServiceImpl pricingChargingInnerServiceImpl;


    @Resource
    ProductParameterQueryServiceImpl productParameterQueryServiceImpl;

    String PCS_CODE = "T19";
    String ROUTE_URI = "direct:T19";
    String ROUTE_DESC = "账户转账交易";
    String ROUTE_ID = "PCS-FLOW-T19";

    String CHECK_TRANS_OUT_MEDIA_CARD_STATUS_CODE = "direct:220";
    String CHECK_TRANS_OUT_MEDIA_CARD_PASSWORD_CODE = "direct:221";
    String CHECK_TRANS_IN_CARD_STATUS_CODE = "direct:222";
    String CHECK_ACCT_WITHDRAWAL_STATUS_CODE = "direct:223";
    String CHECK_ACCT_WITHDRAWAL_LIMIT_AMOUNT_CODE = "direct:224";
    String CHECK_ACCT_DEPOSIT_STATUS_CODE = "direct:225";
    String CHECK_TRANS_OUT_ACCT_DP_DW_CODE = "direct:226";
    String CHECK_TRANS_IN_ACCT_DP_DW_CODE = "direct:227";
    String CHECK_PRODUCT = "direct:228"; ///
    String ACCT_TRANSFER_OUT_CODE = "direct:229";
    String ACCT_TRANSFER_IN_CODE = "direct:230";
    String ACCT_TRANSFER_OUT_REFUND_CODE = "direct:231";
    String ACCT_TRANSFER_IN_REFUND_CODE = "direct:232";
    String PRICING_CHARGING_SERVICE_CODE = "direct:233";
    String UPDATE_TRANS_OUT_ACCT_LIMIT_AMOUNT_CODE = "direct:234";
    String ASYNC_SEND_MESSAGE_CODE = "direct:235";

    String  TO_END_CODE = "direct:T19-END";

    private static final String ORIGINAL_REQUEST_BODY_KEY = "ORIGINAL-REQUEST-BODY";

    ObjectMapper mapper = new ObjectMapper();


    @Override
    public void configure() throws Exception {
        // 事务从交易开始开启还是需要事务的时候才开启？
        // 前一步输出作为下一步输入，骤间强依赖
        // 后续步骤输出需要应用进行缓存，因步骤间的强依赖，步骤顺序调整的，影响数据缓存

        from(ROUTE_URI)
                .routeDescription(ROUTE_DESC)
                .routeId(ROUTE_ID)
                .log("开始执行账户转账交易。")
                .to(CHECK_TRANS_OUT_MEDIA_CARD_STATUS_CODE)
                .to(CHECK_TRANS_OUT_MEDIA_CARD_PASSWORD_CODE)
                .to(CHECK_TRANS_IN_CARD_STATUS_CODE)
                .to(PRICING_CHARGING_SERVICE_CODE)
                .to(CHECK_ACCT_WITHDRAWAL_STATUS_CODE)
                .to(CHECK_ACCT_WITHDRAWAL_LIMIT_AMOUNT_CODE)
                .to(CHECK_ACCT_DEPOSIT_STATUS_CODE)
                .to(CHECK_TRANS_OUT_ACCT_DP_DW_CODE)
                .to(CHECK_TRANS_IN_ACCT_DP_DW_CODE)
                .to(CHECK_PRODUCT)
//                .saga()
//                .timeout(1, TimeUnit.MINUTES)
//                .propagation(SagaPropagation.REQUIRES_NEW)  //使用 exchange 的同步补偿
                .to(ACCT_TRANSFER_OUT_CODE)
                .to(ACCT_TRANSFER_IN_CODE)
                .to(UPDATE_TRANS_OUT_ACCT_LIMIT_AMOUNT_CODE)
                .to(ASYNC_SEND_MESSAGE_CODE)
//                .to(TO_END_CODE)
                .log("账户转账交易执行结束");

        from(CHECK_TRANS_OUT_MEDIA_CARD_STATUS_CODE)
//                .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
                //Caused by: java.lang.ClassNotFoundException: 6227090102100000271
                //.setBody(ExpressionBuilder.bodyExpression("${body['transInCardNo']}"))
                .process(exchange -> {
                    Map<String, Object> requestMsg = (LinkedHashMap<String, Object>)exchange.getIn().getBody();
//                    Req111227 requestMsg = exchange.getIn().getBody(Req111227.class);
//                    exchange.getIn().setBody(requestMsg.getTransOutCardNo(),String.class);
                    //// 缓存源始请求报文体
//                    MDC.put(ORIGINAL_REQUEST_BODY_KEY,mapper.writeValueAsString(requestMsg));
                    exchange.setProperty(ORIGINAL_REQUEST_BODY_KEY,mapper.writeValueAsString(requestMsg));
                    exchange.getIn().setBody(requestMsg.get("transOutCardNo"),String.class);
                })
                .bean(mediaCardFacade, "checkMediaCardStatus").log("检查转出卡状态");


//        from(IMediaCardFacade.CHECK_MEDIA_CARD_PASSWORD_V2_CODE)
//                .bean(mediaCardFacade, "checkMediaCardWithdrawalPassword").log("校验转出卡密码")
//                .setInputType(new InputTypeDefinition().javaClass(MediaCardDTO.class));
        from(CHECK_TRANS_OUT_MEDIA_CARD_PASSWORD_CODE)
                //上一步输出，作为这一步输入
                .process(exchange -> {
                    // 缓存转出卡信息
                    MediaCardDTO mediaCardDTO = exchange.getIn().getBody(MediaCardDTO.class);
//                    MDC.put("trans_out_card",mapper.writeValueAsString(mediaCardDTO));
                    exchange.setProperty("trans_out_card",mediaCardDTO);
                })
                .bean(mediaCardFacade, "checkMediaCardWithdrawalPassword").log("校验转出卡密码");

        from(CHECK_TRANS_IN_CARD_STATUS_CODE)
                .process(exchange -> {
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);
                    exchange.getIn().setBody(requestMsg.getTransInCardNo(),String.class);
                })
                .bean(mediaCardFacade, "checkMediaCardStatus").log("检查转入卡状态");

        from(PRICING_CHARGING_SERVICE_CODE)
                .process(new PricingChargingServiceProcessor())
                .bean(pricingChargingInnerServiceImpl, "pricingChargingService").log("计算转账手续费");

        //
        from(CHECK_ACCT_WITHDRAWAL_STATUS_CODE)
                .process(exchange -> {
                    //缓存计费信息
                    ResultVo<PricingChargeResultVo> pricingChargeResultVo = exchange.getIn().getBody(ResultVo.class);

                    BigDecimal totalFee = pricingChargeResultVo.getData().getTotalFeeAmount();
                    exchange.setProperty("pricing_charge",totalFee);
                    //MDC.put("pricing_charge",String.valueOf(totalFee));

                    // 从缓存取出转出卡信息
                    MediaCardDTO transOutCardDTO = exchange.getProperty("trans_out_card",MediaCardDTO.class);
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);

                    AccountInfoDTO acctDto = new AccountInfoDTO();
                    acctDto.setAccountNo(transOutCardDTO.getAccountNo());

                    acctDto.setTransAmount(requestMsg.getAmount().add(totalFee));
                    exchange.getIn().setBody(acctDto,AccountInfoDTO.class);
                })
                .bean(accountFacade, "checkAcctWithdrawalStatus").log("检查转出账户状态");

        from(CHECK_ACCT_WITHDRAWAL_LIMIT_AMOUNT_CODE)
                .process(new CheckAcctWithdrawalLimitAmountProcessor())
                .bean(accountFacade, "checkAcctDayWithdrawLimit").log("校验转出账户限额");

        from(CHECK_ACCT_DEPOSIT_STATUS_CODE)
                .process(exchange -> {
                    AccountLimitAmtTxSumDTO accountLimitAmtTxSumDTO = exchange.getIn().getBody(AccountLimitAmtTxSumDTO.class);
                    exchange.setProperty("acct_limit_amt_tx",accountLimitAmtTxSumDTO);
                    // 从缓存取出转出卡信息
                    MediaCardDTO transInCardDTO = exchange.getProperty("trans_in_card",MediaCardDTO.class);
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);

                    AccountInfoDTO acctDto = new AccountInfoDTO();
                    acctDto.setAccountNo(transInCardDTO.getAccountNo());
                    acctDto.setCustomerName(requestMsg.getTransInCustName());
                    exchange.getIn().setBody(acctDto,AccountInfoDTO.class);
                })
                .bean(accountFacade, "checkAcctDepositStatus").log("检查转入账户状态");

        from(CHECK_TRANS_OUT_ACCT_DP_DW_CODE)
                .process(exchange -> {
                    //缓存转入账号信息
                    AccountInfoDTO transInAcctDto = exchange.getIn().getBody(AccountInfoDTO.class);
                    exchange.setProperty("trans_in_acct",transInAcctDto);
                    //MDC.put("trans_in_acct",mapper.writeValueAsString(transInAcctDto));
                    // 从缓存取出转出卡信息
                    MediaCardDTO transOutCardDTO = exchange.getProperty("trans_out_card",MediaCardDTO.class);
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);
                    AccountInfoDTO acctDto = new AccountInfoDTO();
                    acctDto.setAccountNo(transOutCardDTO.getAccountNo());
                    acctDto.setInitialBranch(requestMsg.getBranchId());
                    exchange.getIn().setBody(acctDto,AccountInfoDTO.class);
                })
                .bean(accountFacade, "checkAcctOutDpDw").log("检查转出账户通存通兑状态");

        from(CHECK_TRANS_IN_ACCT_DP_DW_CODE)
                .process(exchange -> {
                    // 从缓存取出转出卡信息
                    MediaCardDTO transInCardDTO = exchange.getProperty("trans_in_card",MediaCardDTO.class);
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);
                    AccountInfoDTO acctDto = new AccountInfoDTO();
                    acctDto.setAccountNo(transInCardDTO.getAccountNo());
                    acctDto.setInitialBranch(requestMsg.getBranchId());
                    exchange.getIn().setBody(acctDto,AccountInfoDTO.class);
                })
                .bean(accountFacade, "checkAcctInDpDw").log("检查转入账户通存通兑状态");

        // todo 需增加产品校验流程
        from(CHECK_PRODUCT)
                .process(exchange -> {
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);
                    AccountInfoDTO transOutAcctDto = exchange.getProperty("trans_out_acct", AccountInfoDTO.class);
                    ProductCheckDTO params = new ProductCheckDTO();
                    params.setProductNo(transOutAcctDto.getProductNo());
                    params.setAmount(requestMsg.getAmount().doubleValue());
                    params.setAccountCategory(transOutAcctDto.getAccountCategory());
                    params.setType(2);
                    exchange.getIn().setBody(params, ProductCheckDTO.class);
                })
                .bean(productParameterQueryServiceImpl, "checkAcctProduct").log("产品校验");

        from(ACCT_TRANSFER_OUT_CODE)
//                .saga().propagation(SagaPropagation.MANDATORY)
//                .compensation(ACCT_TRANSFER_OUT_REFUND_CODE)
                .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
//                .sagaService(new InMemorySagaService())
                .process(exchange -> {
                    // 从缓存取出转出账户信息
                    AccountInfoDTO withdrawAccount = exchange.getProperty("trans_out_acct", AccountInfoDTO.class);
                    AccountInfoDTO depositAccount = exchange.getProperty("trans_in_acct", AccountInfoDTO.class);
                    Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);

                    AccountBalanceUpdateDTO paramsDto = buildTransOutAmount(withdrawAccount, depositAccount, requestMsg);
                    paramsDto.setTransNo(UUID.randomUUID().toString());
                    exchange.setProperty("trans-no",paramsDto.getTransNo());

                    BigDecimal totalFee = (BigDecimal)exchange.getProperty("pricing_charge");
                    // 交易金额 * -1
                    paramsDto.setTransAmount((requestMsg.getAmount().add(totalFee)).multiply(new BigDecimal(-1)));

                    MDC.put("ACCT_TRANSFER_OUT_REFUND_PARAMS",mapper.writeValueAsString(paramsDto));// 补偿时MDC内值为null
                    exchange.getIn().setBody(paramsDto,AccountBalanceUpdateDTO.class);
                    // 同步补偿
                    exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                        @Override
                        public void onComplete(Exchange exchange) {
                        }

                        @Override
                        public void onFailure(Exchange exchange) {
                            accountFacade.acctTransferOutRefund(paramsDto);
                        }
                    });
                })
                .bean(accountFacade, "acctTransferOut").log("支取转出账户");


        from(ACCT_TRANSFER_OUT_REFUND_CODE)
                .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
                .process(exchange -> {
                    // 从缓存取出正向逻辑参数
                    String temp = MDC.get("ACCT_TRANSFER_OUT_REFUND_PARAMS");
                    AccountBalanceUpdateDTO paramsDto = mapper.readValue(MDC.get("ACCT_TRANSFER_OUT_REFUND_PARAMS"),
                            AccountBalanceUpdateDTO.class);
                    exchange.getIn().setBody(paramsDto,AccountBalanceUpdateDTO.class);
                })
                .bean(accountFacade, "acctTransferOutRefund").log("支取转出账户，交易异常，回滚支取金额");


        from(ACCT_TRANSFER_IN_CODE)
//                .saga().propagation(SagaPropagation.MANDATORY)
//                .compensation(ACCT_TRANSFER_IN_REFUND_CODE)
                .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
                .process(new AcctTransInProcessor())
                .bean(accountFacade, "acctTransferIn").log("存入转入账户");

        from(ACCT_TRANSFER_IN_REFUND_CODE)
                .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
                .process(new AcctTransInRefundProcessor())
                .bean(accountFacade, "acctTransferInRefund").log("存入转入账户，交易异常，回滚存入金额");

        from(UPDATE_TRANS_OUT_ACCT_LIMIT_AMOUNT_CODE)
                .process(new UpdateTransOutAcctLimitAmountProcessor())
                .bean(accountFacade, "updateAcctDayWithdrawLimit").log("累计转出账户累计额");

        from(ASYNC_SEND_MESSAGE_CODE).transform(new Expression() {
            @Override
            public <T> T evaluate(Exchange exchange, Class<T> type) {
                Resp111227 response = new Resp111227();
                Req111227 request = null;
                try {
                    request = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);
                    response.setTransNo((String)exchange.getProperty("trans-no"));
                    response.setTransInCardNo(request.getTransInCardNo());
                    response.setTransOutCardNo(request.getTransOutCardNo());
                    response.setServiceCharge((BigDecimal)exchange.getProperty("pricing_charge"));
                    response.setAmount(request.getAmount());
                    response.setTransTellerId(request.getTellerId());
                    response.setTransDate(new Date());
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                return (T) response;
            }
        })
                .log("异步发送动户通知");


        // Final actions
//        from(TO_END_CODE).saga().propagation(SagaPropagation.MANDATORY).choice()
//                .when(header("fail").isEqualTo(true)).to("saga:COMPENSATE").end();

    }

    class UpdateTransOutAcctLimitAmountProcessor implements Processor{

        @Override
        public void process(Exchange exchange) throws Exception {
            AccountLimitAmtTxSumDTO accountLimitAmtTxSumDTO = (AccountLimitAmtTxSumDTO)exchange.getProperty("acct_limit_amt_tx");
            Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);
            AccountInfoDTO transOutAcctDto = exchange.getProperty("trans_out_acct",AccountInfoDTO.class);
            AccountLimitAmtTxSumDTO  condition = new AccountLimitAmtTxSumDTO();
            condition.setAccountNo(transOutAcctDto.getAccountNo());
            condition.setLimitAmount((accountLimitAmtTxSumDTO == null ? new BigDecimal(0) :
                    accountLimitAmtTxSumDTO.getLimitAmount()).add(requestMsg.getAmount()));
            String dateStr = exchange.getIn().getHeader("req_date",String.class);
            if(StringUtils.isEmpty(dateStr)){
                condition.setTransDate(new Date());
            }else{
                condition.setTransDate(DateUtils.parseDate(exchange.getIn().
                    getHeader("req_date",String.class),new String[]{"yyyyMMdd"}));}
            exchange.getIn().setBody(condition,AccountLimitAmtTxSumDTO.class);
            exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                @Override
                public void onComplete(Exchange exchange) {

                }

                @Override
                public void onFailure(Exchange exchange) {
                    Optional.ofNullable(accountLimitAmtTxSumDTO).ifPresent(accountLimitAmtTxSumDTO1 ->
                            accountFacade.updateAcctDayWithdrawLimit(accountLimitAmtTxSumDTO));

                }
            });
        }
    }

    class CheckAcctWithdrawalLimitAmountProcessor implements Processor{

        @Override
        public void process(Exchange exchange) throws Exception {

            //缓存转出账号信息
            AccountInfoDTO transOutAcctDto = exchange.getIn().getBody(AccountInfoDTO.class);
            exchange.setProperty("trans_out_acct",transOutAcctDto);
            Req111227 request = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);

            AccountLimitAmtTxSumDTO accountLimitAmtTxSumDTO = new AccountLimitAmtTxSumDTO();
            accountLimitAmtTxSumDTO.setAccountNo(transOutAcctDto.getAccountNo());
            accountLimitAmtTxSumDTO.setTransDate(new Date());
            accountLimitAmtTxSumDTO.setTransAmt(request.getAmount());
            accountLimitAmtTxSumDTO.setDayWithdrawLimit(transOutAcctDto.getDayWithdrawLimit());
            exchange.getIn().setBody(accountLimitAmtTxSumDTO,AccountLimitAmtTxSumDTO.class);
        }
    }

    class PricingChargingServiceProcessor implements Processor{

        @Override
        public void process(Exchange exchange) throws Exception {
            //缓存转入卡信息
            MediaCardDTO transInCardDTO = exchange.getIn().getBody(MediaCardDTO.class);
            exchange.setProperty("trans_in_card",transInCardDTO);

            Req111227 request = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);

            // 定义入参对象
            PricingChargeParamVo pricingChargeParamVo = new PricingChargeParamVo();
            // 计收费标志
            pricingChargeParamVo.setChargeFlag(1);
            // 计费资料
            JiFeiItemVo jiFeiItemVo = new JiFeiItemVo();
            jiFeiItemVo.setBillgCcyCode(request.getCurrency());
            jiFeiItemVo.setChbz("1");
            jiFeiItemVo.setPzzl("");
            pricingChargeParamVo.setJiFeiItemVo(jiFeiItemVo);
            FeeCurrenyCodeVo feeCurrenyCodeVo = new FeeCurrenyCodeVo(); // 费种信息
            feeCurrenyCodeVo.setFeeCode("0000000015");
            feeCurrenyCodeVo.setTransAmount(request.getAmount());
//        	feeCurrenyCodeVo.setTransAmount(new BigDecimal("10000"));
            feeCurrenyCodeVo.setNum(1);
//        	feeCurrenyCodeVo.setDuctPointVal(new BigDecimal("1000"));
            feeCurrenyCodeVo.setDuctPointVal(new BigDecimal("0"));
//        	feeCurrenyCodeVo.setTransCcyCode("156");
            feeCurrenyCodeVo.setTransCcyCode(request.getCurrency());
            feeCurrenyCodeVo.setHasDuctPointVal(new BigDecimal("0"));
//        	feeCurrenyCodeVo.setHasDuctPointVal(new BigDecimal("1000"));
            feeCurrenyCodeVo.setChargeZjSeq(Integer.parseInt("12345"));
            pricingChargeParamVo.setFeeCurrenyCodeVo(feeCurrenyCodeVo);
            ShouFeiItemVo shouFeiItemVo = new ShouFeiItemVo(); // 收费资料
            shouFeiItemVo.setXzbz("1");
            shouFeiItemVo.setKkzh("123456");
            shouFeiItemVo.setSfAmount(new BigDecimal("500"));
            shouFeiItemVo.setSfCcyCode("156");
            shouFeiItemVo.setZzsFlag("0");
            pricingChargeParamVo.setShouFeiItemVo(shouFeiItemVo);
            BusinessSceneInfoVo businessSceneInfoVo = new BusinessSceneInfoVo(); // 业务场景信息
            businessSceneInfoVo.setTransCode("000001099");
            businessSceneInfoVo.setDgdsFlag("1");
            businessSceneInfoVo.setGbdm("CHN");
            businessSceneInfoVo.setJrjgbz("0");
//            businessSceneInfoVo.setCustNo(mediaCardDTO.getCustomerNo());
//            businessSceneInfoVo.setAccountNo(mediaCardDTO.getAccountNo());
            businessSceneInfoVo.setCustNo("000000001");
            businessSceneInfoVo.setAccountNo("99999152739623103214");
            businessSceneInfoVo.setAccountTypeCode("1");
            businessSceneInfoVo.setSaleProductNo("PD152739607487599776");
            businessSceneInfoVo.setProductHyCode("PD15273960748759977");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            String chargeStartDate = "20210101";
            try {
                Date startDate = dateFormat.parse(chargeStartDate);
                businessSceneInfoVo.setChargeStartDate(startDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            String chargeEndDate = "20210101";
            try {
                Date endDate = dateFormat.parse(chargeEndDate);
                businessSceneInfoVo.setChargeEndDate(endDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            businessSceneInfoVo.setChannelCode("00");
            businessSceneInfoVo.setTransOrgNo("801000006");
            businessSceneInfoVo.setDfOrgNo("801000004");
            businessSceneInfoVo.setDfAccountNo("99999152739623103215");
            businessSceneInfoVo.setFyslbh("1111");
            businessSceneInfoVo.setBatchChargeAmount(new BigDecimal("10"));
            businessSceneInfoVo.setBatchChargeNum(Integer.parseInt("1"));
            businessSceneInfoVo.setTransCurrencyCode("156");
            businessSceneInfoVo.setJyjzlx("1");
            businessSceneInfoVo.setJzh("123456789123456");
            Date date = new Date();
            String cmOperCode ="666001";//固定一个柜员号
            businessSceneInfoVo.setTransDate(date);
            businessSceneInfoVo.setTransTime("09:01:11");
            businessSceneInfoVo.setChannelCode("01");
            businessSceneInfoVo.setTransPersonCode(cmOperCode); // 柜员号
            pricingChargeParamVo.setBusinessSceneInfoVo(businessSceneInfoVo);
            // 收费因子,原有代码这块儿逻辑已注掉
            List<FeeYiZiItemVo> feeYiZiItemVoList = new ArrayList<FeeYiZiItemVo>();
            pricingChargeParamVo.setFeeYiZiItemVoList(feeYiZiItemVoList);
            // 差异维度数组
            List<ChaYiWeiDuItemVo> chaYiWeiDuItemVoList = new ArrayList<ChaYiWeiDuItemVo>();
            pricingChargeParamVo.setChaYiWeiDuItemVoList(chaYiWeiDuItemVoList);

            exchange.getIn().setBody(pricingChargeParamVo,PricingChargeParamVo.class);

        }
    }

     class AcctTransInProcessor implements Processor {

         @Override
         public void process(Exchange exchange) throws Exception {
             //获取转出生成的交易流水号
             String transNo = (String)exchange.getProperty("trans-no");
             // 从缓存取出转出账户信息
             AccountInfoDTO withdrawAccount = exchange.getProperty("trans_out_acct", AccountInfoDTO.class);
             AccountInfoDTO depositAccount = exchange.getProperty("trans_in_acct", AccountInfoDTO.class);
             Req111227 requestMsg = mapper.readValue(exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY,String.class),Req111227.class);

             AccountBalanceUpdateDTO paramsDto = buildTransInAmount(withdrawAccount,depositAccount,requestMsg);
             paramsDto.setTransNo(transNo);
             MDC.put("ACCT_TRANSFER_IN_REFUND_PARAMS",mapper.writeValueAsString(paramsDto));
             exchange.getIn().setBody(paramsDto,AccountBalanceUpdateDTO.class);

             exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                 @Override
                 public void onComplete(Exchange exchange) {

                 }

                 @Override
                 public void onFailure(Exchange exchange) {
                     accountFacade.acctTransferInRefund(paramsDto);
                 }
             });
         }
     }

    class AcctTransInRefundProcessor implements Processor {

        @Override
        public void process(Exchange exchange) throws Exception {
            // 从缓存取出转出账户信息 temp is null
            //String temp = MDC.get("ACCT_TRANSFER_IN_REFUND_PARAMS");
            //AccountBalanceUpdateDTO paramsDto = mapper.readValue(MDC.get("ACCT_TRANSFER_IN_REFUND_PARAMS"),
            //        AccountBalanceUpdateDTO.class);

            AccountInfoDTO withdrawAccount = (AccountInfoDTO)exchange.getProperty("trans_out_acct");
            AccountInfoDTO depositAccount = (AccountInfoDTO)exchange.getProperty("trans_in_acct");

            Req111227 requestMsg = mapper.readValue((String)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY),Req111227.class);

//            AccountInfoDTO withdrawAccount = mapper.readValue(MDC.get("trans_out_acct"), AccountInfoDTO.class);
//            AccountInfoDTO depositAccount = mapper.readValue(MDC.get("trans_in_acct"), AccountInfoDTO.class);
//            Req111227 requestMsg = mapper.readValue(MDC.get(ORIGINAL_REQUEST_BODY_KEY),Req111227.class);
            String transNo = exchange.getIn().getBody(String.class);

            AccountBalanceUpdateDTO paramsDto = buildTransInAmount(withdrawAccount, depositAccount, requestMsg);
            paramsDto.setTransNo(transNo);
            exchange.getIn().setBody(paramsDto,AccountBalanceUpdateDTO.class);
        }
    }

    private AccountBalanceUpdateDTO buildTransInAmount(AccountInfoDTO withdrawAccount, AccountInfoDTO depositAccount,
                                                        Req111227 requestMsg){
        AccountBalanceUpdateDTO paramsDto = new AccountBalanceUpdateDTO();
        ValueCopyUtils.beanToBean(depositAccount, paramsDto);

        Date transDate = new Date();
        paramsDto.setOperatorTellerId(requestMsg.getTellerId());
        paramsDto.setTransCode(PCS_CODE);

        paramsDto.setTransDate(transDate);
        paramsDto.setTransTime(transDate);

        paramsDto.setBalance(depositAccount.getBalance());
        // true 存入；false 支取
        paramsDto.setDeposit(true);
        paramsDto.setCurrency(requestMsg.getCurrency());
        paramsDto.setReverseFlag(AccountInfo.REVERSE_FLAG_NORMAL);
        paramsDto.setTransAmount(requestMsg.getAmount());
        paramsDto.setInitiationChannelNo(requestMsg.getChannel());
        paramsDto.setAccessChannelNo(requestMsg.getChannel());
        paramsDto.setCardNo(depositAccount.getCardNo());

        // 支取账户信息
        paramsDto.setTransOutAccountNo(withdrawAccount.getAccountNo());
        paramsDto.setTransOutAccountName(requestMsg.getTransOutCustName());

        return paramsDto;
    }

    private AccountBalanceUpdateDTO buildTransOutAmount(AccountInfoDTO withdrawAccount, AccountInfoDTO depositAccount,
                                                        Req111227 requestMsg){
        AccountBalanceUpdateDTO paramsDto = new AccountBalanceUpdateDTO();
        ValueCopyUtils.beanToBean(withdrawAccount, paramsDto);
        paramsDto.setBalance(withdrawAccount.getBalance());
        // true 存入；false 支取
        paramsDto.setDeposit(false);
        paramsDto.setCurrency(requestMsg.getCurrency());
        paramsDto.setReverseFlag(AccountInfo.REVERSE_FLAG_NORMAL);

        Date transDate = new Date();
        paramsDto.setOperatorTellerId(requestMsg.getTellerId());
        paramsDto.setTransCode(PCS_CODE);
        paramsDto.setTransDate(transDate);
        paramsDto.setTransTime(transDate);
        paramsDto.setInitiationChannelNo(requestMsg.getChannel());
        paramsDto.setAccessChannelNo(requestMsg.getChannel());
        paramsDto.setCardNo(withdrawAccount.getCardNo());

        // 存入账户信息
        paramsDto.setTransOutAccountNo(depositAccount.getAccountNo());
        paramsDto.setTransOutAccountName(requestMsg.getTransInCustName());
        return paramsDto;
    }


//    class CheckMediaCardPasswordExchanger implements Function<Exchange, Object>{
//
//        @Override
//        public Object apply(Exchange exchange) {
//            //exchange.getIn().getBody() LinkedHashMap
//            Req111227 requestMsg = mapper.readValue(mapper.writeValueAsString(exchange.getIn().getBody()), Req111227.class);
//            // requestMsg will be null
//            // Req111227 requestMsg = exchange.getIn().getBody(Req111227.class);
//            MediaCardDTO mediaCardDTO = new MediaCardDTO();
//            mediaCardDTO.setCardNo(requestMsg.getTransOutCardNo());
//            mediaCardDTO.setPassword(requestMsg.getPassword());
//            return requestMsg;
//        }
//
//        @Override
//        public <V> Function<V, Object> compose(Function<? super V, ? extends Exchange> before) {
//            return null;
//        }
//
//        @Override
//        public <V> Function<Exchange, V> andThen(Function<? super Object, ? extends V> after) {
//            return null;
//        }
//    }

//    @Component
//    public class PbsRequestObjectConverter implements TypeConverters {
//        @Converter
//        public MediaCardDTO map2MediaCardDto(Map<String,Object> params){
////            Req111227 requestMsg = mapper.readValue(mapper.writeValueAsString(params), Req111227.class);
//            MediaCardDTO mediaCardDTO = new MediaCardDTO();
//            mediaCardDTO.setCardNo((String)params.get("transOutCardNo"));
//            mediaCardDTO.setPassword((String)params.get("password"));
////            ValueCopyUtils.beanToBean(requestMsg,mediaCardDTO);
//            return mediaCardDTO;
//        }
//    }
}
